package com.jvm.synchronizedp;

// synchronized 作用于实例对象
public class Demo2 {

    int num = 0;

    /**
     *
     * 所谓实例对象锁就是用 synchronized 修饰实例对象的实例方法，
     * 注意是 实例方法 ，不是 静态方法
     */
    /**
     *
     * add()方法是实例方法，两个线程操作 add()时，需要先获取 demo2 的锁，
     * 没有获取到锁的，将等待，直到其他线程释放锁为止
     *
     */
    public synchronized void add() {
        /**
         *
         * num++实际上是分 3 步，
         * 获取 num，然后将 num+1，
         * 然后将结果赋值给 num，
         * 如果 t2 在 t1 读取 num 和 num+1 之间获取了 num 的值，
         * 那么 t1 和 t2 会读取到同样的值，
         * 然后执行 num++，
         * 两次操作之后 num 是相同的值，
         * 最终和期望的结果不一致，造成了线程安全失败，
         * 因此我们对 add 方法加了 synchronized 来保证线程安全
         *
         */
        num++;
    }

    public static class T extends Thread {
        private Demo2 demo2;

        public T(Demo2 demo2) {
            this.demo2 = demo2;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                this.demo2.add();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Demo2 demo2 = new Demo2();

        T t1 = new T(demo2);
        T t2 = new T(demo2);
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(demo2.num);
    }

}
